package cs340.stormtroopers.junitTests.phase4BlackBox;

import cs340.stormtroopers.hypeerweb.ConcreteSendVisitor;
import cs340.stormtroopers.hypeerweb.HyPeerWeb;
import cs340.stormtroopers.hypeerweb.Node;
import cs340.stormtroopers.hypeerweb.Parameters;
import cs340.stormtroopers.hypeerweb.SendVisitor;
import junit.framework.TestCase;

/**
 * Black-box testing of SendVisitor
 * 
 * @author William Highland
 *
 */
public class SendVisitorTest extends TestCase
{
	private static int HYPEERWEB_SIZE = 32;
	
	/**
	 * Equivalence classes (How many steps away from the originating Node)
	 * 	- Node Sending a message to itself (0 steps away)
	 *  - Node Sending a message to a Node that is an immediate connection (1 step away)
	 *  - Node Sending a message to a far away node (2 or more steps away)
	 *  - Node Sending a message to a Node that is not in the HyPeerWeb
	 */
	public void testSendEquivalenceClasses()
	{
		HyPeerWeb hypeerweb = HyPeerWeb.getSingleton();
		createHyPeerWeb(hypeerweb);
		
		Node startNode = hypeerweb.getNode(2);
		ConcreteSendVisitor sendVisitor = new ConcreteSendVisitor();
		
		//First equivalence class: A node sending a message to itself
		Parameters parameters = SendVisitor.createInitialParameters(2);
		parameters.set("message", "Message 2:2");
		startNode.accept(sendVisitor, parameters);

		assertTrue(startNode.getContents().containsValue("Message 2:2"));
		
		//Check that it needed 0 steps to finish visiting
		//The target Node counts as a part of the Path
		System.out.println(sendVisitor.getStringPath());
		assertTrue(sendVisitor.getPath().size() == 1);
		
		parameters.clear();
		
		//2nd equivalence class: A node sending a message to a Node that it is connected to 
		//3 is a neighbor of 2
		sendVisitor = new ConcreteSendVisitor();
		parameters = SendVisitor.createInitialParameters(3);
		parameters.set("message", "Message 2:3");
		startNode.accept(sendVisitor, parameters);
		
		assertTrue(hypeerweb.getNode(3).getContents().containsValue("Message 2:3"));
		System.out.println(sendVisitor.getStringPath());

		assertTrue(sendVisitor.getPath().size() == 2);
		
		//3rd equivalence class: A node sending a message to a Node that is 2 or more steps away
		//12 is 4 steps away from 2
		sendVisitor = new ConcreteSendVisitor();
		parameters = SendVisitor.createInitialParameters(12);
		parameters.set("message", "Message 2:12");
		startNode.accept(sendVisitor, parameters);
		
		assertTrue(hypeerweb.getNode(12).getContents().containsValue("Message 2:12"));
		System.out.println(sendVisitor.getStringPath());

		assertTrue(sendVisitor.getPath().size() == 4);
		
		//4th equivalence class: A node sending a message to a Node that is not in the HyPeerWeb
		sendVisitor = new ConcreteSendVisitor();
		parameters = SendVisitor.createInitialParameters(-1);
		parameters.set("message", "Invalid");
		startNode.accept(sendVisitor, parameters);
		
		//Ensure that no Nodes in the HyPeerWeb have the invalid message
		for(int i = 0; i < HYPEERWEB_SIZE; i++)
		{
			assertFalse(hypeerweb.getNode(i).getContents().containsValue("Invalid"));
		}
		System.out.println(sendVisitor.getStringPath());
		assertTrue(sendVisitor.getPath().size() == 1);
	}
	
	public void testSendVisitor()
	{
		HyPeerWeb hypeerweb = HyPeerWeb.getSingleton();
		createHyPeerWeb(hypeerweb);
		int totalTests = 1;
		
		for(int i = 0; i < HYPEERWEB_SIZE; i++)
		{
			Node startNode = hypeerweb.getNode(i);

			for(int j = 0; j < HYPEERWEB_SIZE; j++)
			{
				if(i == 0 && j == 0)
				{			
					ConcreteSendVisitor sendVisitor = new ConcreteSendVisitor();
	
					//This will print out an error. That's for cobertura
					Parameters parameters = new Parameters();
					parameters.set("message", "Message1");
					startNode.accept(sendVisitor, parameters);
				}
				else if (i == 1 && j==1)
				{
					ConcreteSendVisitor sendVisitor = new ConcreteSendVisitor();
	
					//This will print out an error. That's for cobertura
					Parameters parameters = new Parameters();
					startNode.accept(sendVisitor, parameters);
				}
				if(j != i)
				{
					Node endNode = hypeerweb.getNode(j);
					ConcreteSendVisitor sendVisitor = new ConcreteSendVisitor();


					Parameters parameters = SendVisitor.createInitialParameters(j);
					parameters.set("message", "Message " + (i+j));

					startNode.accept(sendVisitor, parameters);
					int distance = Integer.bitCount(startNode.getWebIdValue() ^ endNode.getWebIdValue());

					//Ensure the target node got the correct message and the path taken was optimal
					assertTrue(distance >= (sendVisitor.getPath().size()-1));
					assertTrue(endNode.getContents().containsValue("Message " + (i+j)));
					totalTests++;

					//Get the String path for 100% cobertura
					String path = sendVisitor.getStringPath();
					System.out.println(path);
				}
			}
		}		
	}
	
	private void createHyPeerWeb(HyPeerWeb hypeerweb)
	{
		Node startNode = new Node(0);
		hypeerweb.addNode(startNode);

		for(int i = 1; i < HYPEERWEB_SIZE; i++)
		{
			Node nodeToAdd = new Node(i);
			startNode.addToHyPeerWeb(nodeToAdd);
		}
	}

}
